package com.clementheliou.cheliou.business.technical.security.authentication.impl;

import java.awt.Toolkit;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.clementheliou.cheliou.business.dataaccess.member.MemberDataAccessService;
import com.clementheliou.cheliou.business.technical.security.authentication.AuthenticationDetailsTechnicalService;
import com.clementheliou.cheliou.business.technical.security.authentication.model.AuthenticationDetails;
import com.clementheliou.cheliou.dal.model.member.Member;
import com.clementheliou.cheliou.dal.model.member.enumeration.MemberRole;

/**
 * Spring Security-based service used to manage core data about the authenticated user. Due to the
 * {@link Transactional} annotation and the value of its <i>readOnly</i> attribute, all methods are
 * called in a transaction that will be rollbacked in the end. This behavior can be overriden at the
 * method level, more particularly if you need to perform an insert, update or delete action.
 * 
 * @author Clément HELIOU (clement.heliou@gmail.com)
 * @see {@link AuthenticationDetailsTechnicalService};
 * @see {@link Service};
 * @see {@link Transactional}.
 * @since 1.0
 */
@Service
@Transactional(readOnly = true)
public class AuthenticationDetailsSpringSecurityTechnicalService implements AuthenticationDetailsTechnicalService {

	/**
	 * Logger for this class.
	 * 
	 * @author Clément HELIOU (clement.heliou@gmail.com)
	 * @see {@link Logger};
	 * @see {@link LoggerFactory}.
	 * @since 1.0
	 */
	private static final Logger LOGGER = LoggerFactory.getLogger(AuthenticationDetailsSpringSecurityTechnicalService.class);

	/**
	 * Data access service dedicated to the members.
	 * 
	 * @author Clément HELIOU (clement.heliou@gmail.com)
	 * @since 1.0
	 */
	@Autowired
	private MemberDataAccessService memberDataAccessService;

	/**
	 * {@inheritDoc}
	 * 
	 * @author Clément HELIOU (clement.heliou@gmail.com)
	 * @since 1.0
	 */
	public AuthenticationDetails getCurrentUser() {
		final Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
		AuthenticationDetails userDetails = new AuthenticationDetails();

		if (authentication != null && !authentication.getAuthorities().contains(new SimpleGrantedAuthority(MemberRole.ANONYMOUS.getCode()))) {
			userDetails = ((AuthenticationDetails) authentication.getPrincipal());
			userDetails.setPassword(null);
		} else {
			userDetails.setScreenSize(Toolkit.getDefaultToolkit().getScreenSize());
		}

		return userDetails;
	}

	/**
	 * <i> {@inheritDoc} </i>
	 * <p>
	 * In our implementation, the login's role is played by the email.
	 * </p>
	 * 
	 * @author Clément HELIOU (clement.heliou@gmail.com)
	 * @see {@link #loadAuthenticationDetailsByEMail(String)}.
	 * @since 1.0
	 */
	@Override
	public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
		return loadAuthenticationDetailsByEMail(username);
	}

	/**
	 * {@inheritDoc}
	 * 
	 * @author Clément HELIOU (clement.heliou@gmail.com)
	 * @since 1.0
	 */
	public AuthenticationDetails loadAuthenticationDetailsByEMail(final String email) throws UsernameNotFoundException {
		LOGGER.debug("Load user by email {}.", email);
		final Member member = memberDataAccessService.getMemberByEMail(email);

		if (null == member) {
			throw new UsernameNotFoundException(StringUtils.EMPTY);
		}

		final AuthenticationDetails userDetails = new AuthenticationDetails();

		userDetails.setAccountNonExpired(true);
		userDetails.setAccountNonLocked(true);
		userDetails.setCredentialsNonExpired(true);
		userDetails.setEnabled(true);
		userDetails.setFirstName(member.getFirstName());
		userDetails.setMemberId(member.getId());
		userDetails.setMemberLocale(member.getLocale());
		userDetails.setName(member.getName());
		userDetails.setPassword(member.getPassword());
		userDetails.setScreenSize(Toolkit.getDefaultToolkit().getScreenSize());
		userDetails.setUsername(member.getEmail());

		for (MemberRole role : member.getRolesList()) {
			userDetails.getAuthorities().add(new SimpleGrantedAuthority(role.getCode()));
		}

		return userDetails;
	}

}
